package cn.uncode.rpc.filter;

import cn.uncode.rpc.common.CommonConstant;
import cn.uncode.rpc.common.log.Logger;
import cn.uncode.rpc.common.log.LoggerFactory;
import cn.uncode.rpc.core.Invoker;
import cn.uncode.rpc.core.Request;
import cn.uncode.rpc.core.Response;
import cn.uncode.rpc.core.URLParam;
import cn.uncode.rpc.spi.SpiMeta;
import cn.uncode.rpc.util.NetUtil;
import cn.uncode.rpc.util.StringTools;

/**
 * <pre>
 * Access log filter
 *
 * 统计整个call的执行状况，尽量到最上层，最后执行.
 * 此filter会对性能产生一定影响，请求量较大时建议关闭。
 *
 * </pre>
 * 
 * @author fishermen
 * @version V1.0 created at: 2013-5-22
 */
@SpiMeta(name = "access", sequence = 100)
public class AccessLogFilter implements Filter {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(AccessLogFilter.class);

    private String side;

    @Override
    public Response filter(Invoker<?> invoker, Request request) {
        boolean needLog = invoker.getUrl().getBooleanParameter(URLParam.ACCESS_LOG.getName(), URLParam.ACCESS_LOG.getBooleanValue());
        if (needLog) {
            long t1 = System.currentTimeMillis();
            boolean success = false;
            try {
                Response response = invoker.invoke(request);
                success = true;
                return response;
            } finally {
                long consumeTime = System.currentTimeMillis() - t1;
                logAccess(invoker, request, consumeTime, success);
            }
        } else {
            return invoker.invoke(request);
        }
    }

    private void logAccess(Invoker<?> invoker, Request request, long consumeTime, boolean success) {
        if (getSide() == null) {
//            String side = caller instanceof Provider ? CommonConstant.NODE_TYPE_SERVICE : CommonConstant.NODE_TYPE_REFERER;
            setSide(side);
        }

        StringBuilder builder = new StringBuilder(128);
        append(builder, side);
        append(builder, invoker.getUrl().getParameter(URLParam.APPLICATION.getName()));
        append(builder, invoker.getUrl().getParameter(URLParam.MODULE.getName()));
        append(builder, NetUtil.getLocalAddress().getHostAddress());
        append(builder, request.getInterfaceName());
        append(builder, request.getMethodName());
        append(builder, request.getParamtersDesc());
        // 对于client，url中的remote ip, application, module,referer 和 service获取的地方不同
        if (CommonConstant.NODE_TYPE_REFERER.equals(side)) {
            append(builder, invoker.getUrl().getHost());
            append(builder, invoker.getUrl().getParameter(URLParam.APPLICATION.getName()));
            append(builder, invoker.getUrl().getParameter(URLParam.MODULE.getName()));
        } else {
            append(builder, request.getAttachments().get(URLParam.HOST.getName()));
            append(builder, request.getAttachments().get(URLParam.APPLICATION.getName()));
            append(builder, request.getAttachments().get(URLParam.MODULE.getName()));
        }

        append(builder, success);
        append(builder, request.getAttachments().get(URLParam.REGISTRY_RETRY_PERIOD.getName()));
        append(builder, consumeTime);

        LOGGER.trace(builder.substring(0, builder.length() - 1));
    }

    private void append(StringBuilder builder, Object field) {
        if (field != null) {
            builder.append(StringTools.urlEncode(field.toString()));
        }
        builder.append(CommonConstant.SEPERATOR_ACCESS_LOG);
    }

    public String getSide() {
        return side;
    }

    public void setSide(String side) {
        this.side = side;
    }



}
